home *** CD-ROM | disk | FTP | other *** search
- { ACCURACY.PAS: 8087 math accuracy test, v 1.7, Oct 1987
- (c) 1987, PC Tech Journal and Ziff Communications Co.
- written by Jim Roberts.
-
- Uncomment the correct constant declarations for your compiler.
- Insert correct version number in `compil' variable,
- name of hardware system & math coprocessor in `machin' variable.
-
- }
- { $MC68020+}
- { $MC68881+}
- {$R+}
- {$U-}
-
- program ACCURACY2;
-
-
- USES
-
- Memtypes, QuickDraw, OSIntf, ToolIntf, PackIntf, SANE, MacExtras;
-
- TYPE
- accarray = array[1..5] of extended ;
-
-
- CONST
- compil = 'Macintosh Turbo Pascal' ;
- machin = 'Macintosh II' ;
- minerr = 1.0E-17 ;
- logmin = 17.0 ;
- n = 10 ;
- y = 1.0 ;
- step = 0.2 ;
- iter = 20 ;
- itertrig = 5 ;
- log10e = 0.43429448190325182765 ;
- pi = 3.14159265358979323846 ;
- piO2 = 1.57079632679489661923 ;
- root2 = 1.4142135623730950488 ;
- root3 = 1.7320508075688772935 ;
- sqrtO2 = 0.7071067811865475244 ;
-
- VAR
- i, j, k, l, m, ntest,z : integer ;
- a,b,c : array[1..N,1..N] of extended;
- sum, X : extended ;
- xx, zz, quot : extended ;
- a0, a1, d0, d1, frac : extended ;
- p, p2 : extended ;
- th, err, logerr, diverr,
- val, funct : accarray ;
- testerr : array[1..10] of extended ;
- toterr : extended ;
- done : Boolean;
- s : DecStr;
- textWidth : INTEGER; { Maximum width of a character }
- textHeight : INTEGER; { Height of a character }
- f : DecForm;
-
-
-
- PROCEDURE DrawAt( x, y : INTEGER; s : Str255 );
-
- { Draw string at this coordinate, similar to an x,y location }
- { on a conventional computer terminal. }
-
- CONST
-
- Xoffset = 5; { Blank pixels in left border }
- Yoffset = 12; { Blank pixels in top border }
-
- BEGIN
- MoveTo( Xoffset + x * textWidth , Yoffset + y * textHeight );
- DrawString( s )
- END; { DrawAt }
-
- PROCEDURE NewFont( fontNumber, pointSize : INTEGER );
-
- { Select new font and adjust variables for DrawAt }
-
-
- BEGIN
- TextFont( fontNumber ); { Use new font }
- TextSize( pointSize ); { Use new size }
- textHeight := pointSize + 2; { Calc new character height }
- textWidth := CharWidth( 'M' ) { Calc width of widest char }
- END; { NewFont }
-
-
-
- procedure filla;
- var
- i,j : integer;
- begin
- for i := 1 to N do
- for j := 1 to N do
- if i <> j then a[i,j] := Y
- else a[i,j] := X + Y;
- end;
-
- procedure fillb;
- var
- i,j : integer;
- f,d : extended ;
- begin
- f := X + N*Y ;
- d := 1.0/(X*f) ;
- for i := 1 to N do
- for j := 1 to N do
- if i <> j then b[i,j] := -Y*d
- else b[i,j] := (-Y+f)*d ;
- end;
-
- procedure fillc;
- var
- i,j : integer;
- begin
- for i := 1 to N do
- for j := 1 to N do
- c[i,j] := 0.0;
- end;
-
- procedure mult;
- var
- i, j, k : integer;
- begin
- for i := 1 to N do
- for j := 1 to N do
- begin
- sum := 0.0;
- for k := 1 to N do
- sum := sum + a[i,k] * b[k,j];
- c[i,j] := sum;
- end;
- end;
-
- procedure sumit ;
- var
- i, j : integer;
- begin
- sum := 0.0;
- for i := 1 to N do c[i,i] := c[i,i] - 1.0 ;
- for i := 1 to N do
- for j := 1 to N do
- sum := sum + abs(c[i,j]);
- end;
-
- function osgn(n:integer) : extended ; {negative if n odd}
- begin
- if n = 2*(n div 2) then osgn := 1.0
- else osgn := -1.0 ;
- end;
-
-
-
- procedure arith ;
- {TEST 1: well-conditioned combinatorial matrix times its inverse.}
- var
- i, k, l, m : integer ;
- begin
- zz := 0.30 ; {factor used to control decrease of condition of matrix}
- for l := 1 to 5 do
- begin
- xx := zz*(3-l) ;
- X := exp(xx/LOG10E); {slowly decreases conditioning}
- filla ; fillb ; fillc ;
- mult ; sumit ;
- err[l] := sum/sqr(N) ; {error is average absolute error per element}
- if err[l] > MINERR then logerr[l] := -ln(err[l]) * LOG10E
- else logerr[l] := LOGMIN;
- testerr[1] := testerr[1] + (LOGMIN - logerr[l]) ;
- end ;
- testerr[1] := testerr[1]/5.0 ;
-
- DrawAt(5,21,'#1a: 10x10 matrix ');
- f.Style := FixedDecimal;
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,21,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[1],s);
- DrawAt(59,21,s);
-
- { infinite product for 1-x: run in reverse to test division }
-
- sum := 0.0 ;
- for l := 1 to 5 do
- begin
- xx := (1 - l) / 4.0 ;
- zz := exp((xx-2.0)/LOG10E); {increases number of factors for convergence}
- xx := 1.0 - zz ; { zz ≈ .01 => loss of 2 sig figs }
- {The following formula for the number of factors is designed to give
- sufficient accuracy, while avoiding underflow in the powers of xx.
- It gives a more uniform computation from compiler to compiler.}
- m := 12+l ;
- quot := 1.0 ;
- for k := 1 to m do
- begin
- quot := quot / (1.0 + xx) ;
- xx := xx * xx ;
- end ;
- err[l] := abs(1.0 - quot/zz)*0.01 ;
- { factor of 0.01 to compensate for cancellation errors }
- if err[l] > MINERR then diverr[l] := -ln(err[l]) * LOG10E
- else diverr[l] := LOGMIN;
- sum := sum + (LOGMIN - diverr[l]) ;
- logerr[l] := diverr[l] ; {needed for later average}
- end ;
- sum := sum / 5.0 ;
-
-
- DrawAt(5,22,'#1 : infinite product ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,diverr[i],s);
- DrawAt(z,22,s);
- end;
- f.Digits := 2;
- Num2Str(f,sum,s);
- DrawAt(59,22,s);
-
-
- { test continued fraction for tangent against exact values for five angles:
- this is a test of division and subtraction, not of the tangent.}
-
- th[1] := PI/12.0 ;
- th[2] := PI/6.0 ;
- th[3] := PI/4.0 ;
- th[4] := PI/3.0 ;
- th[5] := 5.0*PI/12.0 ;
- val[1] := 2.0 - ROOT3 ;
- val[2] := 1.0 / ROOT3 ;
- val[3] := 1.00 ;
- val[4] := ROOT3 ;
- val[5] := 2.0 + ROOT3 ;
- sum := 0.0 ;
- m := 8 ; { this number of iterations gives sufficient accuracy }
- for l := 1 to 5 do
- begin
- a0 := 2.0 * m + 1.0 ;
- p2 := th[l] ;
- p := sqr(p2) ;
- d0 := a0 - p / (a0 + 2.0) ;
- for k := 1 to m do
- begin
- a1 := a0 - 2.0 ;
- d1 := a1 - p / d0 ;
- a0 := a1 ;
- d0 := d1 ;
- end ;
- frac := p2 / d0 ;
- funct[l] := frac ;
- end ;
-
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - val[l]/funct[l]) ;
- if err[l] > MINERR then diverr[l] := -ln(err[l]) * LOG10E
- else diverr[l] := LOGMIN;
- sum := sum + (LOGMIN - diverr[l]);
- end ;
- sum := sum / 5.0 ;
-
-
- DrawAt(5,23,'#1 : continued fraction ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,diverr[i],s);
- DrawAt(z,23,s);
- end;
- f.Digits := 2;
- Num2Str(f,sum,s);
- DrawAt(59,23,s);
-
- for i := 1 to 5 do
- begin
- logerr[i] := 0.5*(logerr[i] + diverr[i]) ;
- testerr[2] := testerr[2] + (LOGMIN - logerr[i]);
- end ;
- testerr[2] := testerr[2]/5.0 ;
-
- DrawAt(5,24,'#1b: division average ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,24,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[2],s);
- DrawAt(59,24,s);
-
- end;
-
-
- procedure trig ; {TEST 2: first, errors in some sine identities }
- var
- i, j, k, l : integer ;
- begin
- for l := 1 to 5 do logerr[l] := 0.0 ;
- for j := 1 to ITERTRIG do
- begin
- p := j - 1 ;
- th[1] := PI/12.0 + p*PI ;
- th[2] := PI/6.0 + p*PI ;
- th[3] := PI/4.0 + p*PI ;
- th[4] := PI/3.0 + p*PI ;
- th[5] := 5.0*PI/12.0 + p*PI ;
- val[1] := osgn(j-1)*ROOT2*(ROOT3-1.0)*0.25 ;
- val[2] := osgn(j-1)*0.5 ;
- val[3] := osgn(j-1)*SQRTO2 ;
- val[4] := osgn(j-1)*0.5*ROOT3 ;
- val[5] := osgn(j-1)*ROOT2*(ROOT3+1.0)*0.25 ;
- for l := 1 to 5 do funct[l] := sin(th[l]) ;
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - val[l]/funct[l]) ;
- if err[l] > MINERR then logerr[l] := logerr[l] - ln(err[l]) * LOG10E
- else logerr[l] := logerr[l] + LOGMIN ;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / ITERTRIG ;
- for l := 1 to 5 do testerr[3] := testerr[3] + (LOGMIN - logerr[l]);
- testerr[3] := testerr[3]/5.0 ;
-
- DrawAt(5,25,'#2a: sine function ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,25,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[3],s);
- DrawAt(59,25,s);
-
- { compare sin()/cos() with exact values for tan() }
- for l := 1 to 5 do logerr[l] := 0.0 ;
- for j := 1 to ITERTRIG do
- begin
- p := j - 1 ;
- th[1] := PI / 12.0 + (j-1)*PI ;
- th[2] := PI / 6.0 + (j-1)*PI ;
- th[3] := PI / 4.0 + (j-1)*PI ;
- th[4] := PI / 3.0 + (j-1)*PI ;
- th[5] := 5.0 * PI / 12.0 + (j-1)*PI ;
- val[1] := 2.0 - ROOT3 ;
- val[2] := 1.0 / ROOT3 ;
- val[3] := 1.00 ;
- val[4] := ROOT3 ;
- val[5] := 2.0 + ROOT3 ;
- for l := 1 to 5 do funct[l] := sin(th[l])/cos(th[l]) ;
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - val[l]/funct[l]) ;
- if err[l] > MINERR then logerr[l] := logerr[l] - ln(err[l]) * LOG10E
- else logerr[l] := logerr[l] + LOGMIN ;
- end ;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / ITERTRIG ;
- for l := 1 to 5 do
- testerr[4] := testerr[4] + (LOGMIN - logerr[l]) ;
- testerr[4] := testerr[4]/5.0 ;
-
- DrawAt(5,26,'#2b: tangent|sin()/cos()');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,26,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[4],s);
- DrawAt(59,26,s);
-
-
- { compare arctan() with tan() for consistency }
- for l := 1 to 5 do logerr[l] := 0.0 ;
- for j := 1 to ITER do
- begin
- for l := 1 to 5 do th[l] := (5*j+l-5)*PIO2/(5*ITER+1) ;
- for l := 1 to 5 do val[l] := sin(th[l])/cos(th[l]) ;
- for l := 1 to 5 do funct[l] := arctan(val[l]) ;
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - th[l]/funct[l]) ;
- if err[l] > MINERR then logerr[l] := logerr[l] - ln(err[l]) * LOG10E
- else logerr[l] := logerr[l] + LOGMIN ;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / ITER ;
- for l := 1 to 5 do
- testerr[5] := testerr[5] + (LOGMIN - logerr[l]);
- testerr[5] := testerr[5]/5.0 ;
-
- DrawAt(5,27,'#2c: arctan function ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,27,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[5],s);
- DrawAt(59,27,s);
-
- end;
-
-
- procedure transc ; {TEST 3: ln() and exp() for consistency}
- var
- i, j, l : integer ;
- begin
- for l := 1 to 5 do logerr[l] := 0.0 ;
- for j := 1 to ITER do
- begin
- for l := 1 to 5 do th[l] := (5*j+l-5)*STEP ;
- for l := 1 to 5 do val[l] := exp(th[l]) ;
- for l := 1 to 5 do funct[l] := ln(val[l]) ;
-
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - th[l]/funct[l]) ;
- if err[l] > MINERR then logerr[l] := logerr[l] - ln(err[l]) * LOG10E
- else logerr[l] := logerr[l] + LOGMIN;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / ITER ;
- for l := 1 to 5 do
- testerr[6] := testerr[6] + (LOGMIN - logerr[l]);
- testerr[6] := testerr[6]/5.0 ;
-
- DrawAt(5,28,'#3a: ln() & exp() ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,28,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[6],s);
- DrawAt(59,28,s);
-
- end;
-
-
- procedure roots ; { sqrt() and sqr() identities }
- var
- i, j, l : integer ;
- begin
- for l := 1 to 5 do logerr[l] := 0.0 ;
- for j := 1 to ITER do
- begin
- for l := 1 to 5 do th[l] := (5*j+l-5)*STEP ;
- for l := 1 to 5 do val[l] := sqrt(th[l]) ;
- for l := 1 to 5 do funct[l] := sqr(val[l]) ;
-
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - th[l]/funct[l]) ;
- if err[l] > MINERR then logerr[l] := logerr[l] - ln(err[l]) * LOG10E
- else logerr[l] := logerr[l] + LOGMIN;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / ITER ;
- for l := 1 to 5 do
- testerr[7] := testerr[7] + (LOGMIN - logerr[l]) ;
- testerr[7] := testerr[7]/5.0;
-
- DrawAt(5,29,'#3b: sqrt() & sqr() ');
- f.Digits := 1;
- z := 26;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f,logerr[i],s);
- DrawAt(z,29,s);
- end;
- f.Digits := 2;
- Num2Str(f,testerr[7],s);
- DrawAt(59,29,s);
-
- end;
-
-
- procedure Initialize;
- { Perform one-time setup work. }
- var
- r: Rect;
- MyNewWindow: WindowPtr;
- begin
- InitGraf(@thePort); { initialize QuickDraw }
- InitFonts; { " Font Manager }
- InitWindows; { " Window Manager }
- InitCursor; { make cursor an arrow }
- done := False;
- SetRect(r,30,60,600,400);
- MyNewWindow:=NewWindow(nil,r,'Accuracy Tester',True,documentProc,Pointer(-1),True,0);
- MyNewWindow^.txFace := [bold]; MyNewWindow^.txFont := SystemFont;
- windowPeek(MyNewWindow)^.refCon := Longint(NewString('Contents of window 1'));
-
- end;
-
- procedure Header ;
- begin
- NewFont ( monaco, 9 );
- TextFace( [] );
- DrawAt(5,6,'ACCURACY: extended tester: ' + COMPIL + '; ' + MACHIN) ;
- DrawAt(5,7,' V 1.7 (c) 1987, PC Tech Journal and Ziff Communications Co.');
- DrawAt(5,8,' written by Jim Roberts.');
- DrawAt(5,9,' Modified for Macintosh & Turbo Pascal by Morry Hodges, CIS 74766,3426');
- DrawAt(5,10,'Test 1 checks multiplication and addition, then division and subtraction.');
- DrawAt(5,11,'Test 2 measures the accuracy of the Turbo trig functions (there is no tan()).');
- DrawAt(5,12,'Test 3 finds the truncation error in some exponential and sqrt identities.');
- DrawAt(5,13,'ACCURACY is the rounded negative log of error. Program may exit abnormally.');
- DrawAt(5,14,'NOTE: an increase of 1 in the rating means a factor of TEN less accurate.');
- DrawAt(5,16,'Interpretation <0.0 - 0.5 => Excellent 1.0 - 1.5 => Fair');
- DrawAt(5,17,' of RATING: 0.5 - 1.0 => Good 1.5 < => Poor');
- DrawAt(5,18,'') ;
- DrawAt(5,19,' TESTS ACCURACY RATING ');
- end;
-
- begin { program ACCURACY begins here }
- Repeat
- Initialize;
- Header ;
- for i := 1 to 10 do testerr[i] := 0.0 ;
- arith ;
- trig ;
- transc ;
- roots ;
- ntest := 7 ;
- toterr := 0.0;
- for i := 1 to ntest do toterr := toterr + testerr[i] ;
- toterr := toterr/ntest ;
- DrawAt(5,31,'Overall rating:');
- Num2Str(f,toterr,s);
- DrawAt(23,31,s);
- DrawAt(5,33,'Click mouse to finish');
- Pause;
- until Button;
- END.
-
-
-